Skip to content

Document grouped (ColGroup) columns in search downloads - #30

Closed
roed-math wants to merge 3 commits into
mainfrom
ai/t40-colgroup-download-docs
Closed

Document grouped (ColGroup) columns in search downloads#30
roed-math wants to merge 3 commits into
mainfrom
ai/t40-colgroup-download-docs

Conversation

@roed-math

@roed-math roed-math commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Search-result downloads describe each column in a header comment and in a definitions section at the
bottom of the file. For sections whose columns are grouped with a ColGroup that downloads as a nested
list of its subcolumns' values (the abstract subgroup search: Subgroup/Ambient/Quotient), the
header listed only the group titles ([Label, Subgroup, Ambient, Quotient]) and the definitions loop
skipped the groups entirely (their knowl is None), so the individual subcolumns were never described.

This adds SearchCol.download_subcols (overridden in ColGroup), which identifies exactly the groups
that download as a nested list, and builds one ColumnSchema per downloaded column in
Downloader.make_schema. That single schema is then shared by the three places where a download file
describes its own contents:

  • the header comment spells out each group's subcolumns under "where the grouped columns are themselves
    lists";
  • the definitions section documents every subcolumn (short title, storage name, knowl or
    download_desc);
  • assign_columns now receives the schema, so the CSV header row, which has no comments to fall back
    on, annotates each grouped cell with its ordered subcolumn names, for example
    ambient_cols [ambient_name, ambient_order]. There is still exactly one CSV field per top-level
    column, so the shape of the data is unchanged, and the existing knowl hyperlinks are preserved.

The first entry of each group is a MultiProcessedCol that downloads the raw [label, TeX name] pair
rather than the displayed link, so sub_name, ambient_name and quotient_name now carry a
download_desc spelling that pair out, including the cases where the label is null (the group is not in
the LMFDB) and where both entries are null (the quotient of a non-normal subgroup).

ColGroups that set download_col (cmf traces/Atkin-Lehner, conjugacy class powers) download as a
single value and are unchanged, as are all non-grouped columns.

New automated coverage:

  • test_subgroup_search_download_text: the top-level form, the ordered group expansions (first and last
    subcolumn plus representative ones in between, so a truncated or reordered expansion fails), the
    grouped-column introductions, the per-subcolumn definitions, the [label, TeX name] descriptions, and
    that each downloaded row matches the documented top-level and per-group lengths.
  • test_subgroup_search_download_csv: parsed with the csv module. Four header fields, the ordinary
    label cell still just its knowl hyperlink, each grouped cell listing its subcolumns in order, and
    every data row with the same field count as the header.
  • test_scalar_colgroup_download: cmf traces/atkin_lehner and conjugacy class power_cols keep
    their download_col, report no subcolumns and download a single value, while the three subgroup
    groups do expand.
  • test_download_subcols in lmfdb/tests/test_utils.py: the API contract, namely ordinary column to
    [], static group without download_col to its ordered subcolumns, and static or callable group with
    download_col to [].

Verified by generating subgroup downloads in all seven offered formats (text, csv, sage, magma, gp, gap,
oscar) and checking that number field (ordinary columns) and cmf (scalar ColGroups) downloads are
byte-identical in all seven formats to before this change. All four new tests fail against the download
machinery as it was before this branch. pyflakes, pylint (with CI's flags) and ruff are clean.

Addresses LMFDB#6477.

🤖 Generated with Claude Code

Search-result downloads describe each column in a header comment and a
definitions section at the bottom of the file.  For sections whose columns
are grouped with a ColGroup and downloaded as a nested list of subcolumn
values (the abstract subgroup search: Subgroup/Ambient/Quotient), the header
listed only the group titles (e.g. [Label, Subgroup, Ambient, Quotient]) and
the definitions loop skipped the groups entirely (their knowl is None), so the
individual subcolumns were never described.

Add SearchCol.download_subcols(info) (overridden in ColGroup) that returns a
group's subcolumns exactly when it downloads as a nested list (download_col is
None and subcols is a concrete list); ColGroups that set download_col
(cmf traces/atkin_lehner, cc power_cols) download as a single value and are
unchanged.  In downloader.py, use it to (a) spell out each grouped column's
subcolumn titles under the "Each entry ... has the form" comment and (b) expand
each grouped column in the definitions section, documenting every subcolumn by
its short title, name and knowl.

Verified by generating sage/magma/gp/text downloads for the subgroup search
(now documents all 18/2/11 subcolumns matching the data), plus regressions for
cmf newforms, conjugacy classes and number fields (byte-identical headers); the
downloaded sage/gp/magma files parse and run.  cmf + abstract-group + number
field download tests pass; pyflakes/ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
roed314 and others added 2 commits August 4, 2026 17:23
…MFDB#6477)

Addresses review feedback on the grouped (ColGroup) download documentation.

The schema of a download existed only as prose passed to lang.comment, which
CSVLanguage drops (CSV has no comment syntax), so a CSV subgroup download still
had a header of just [label, subgroup_cols, ambient_cols, quotient_cols] over
cells holding nested lists.  Downloader.make_schema now builds one ColumnSchema
per downloaded column (storage name, title, and the ordered subcolumn schemas
when the column downloads as a nested list), and that object drives all three
places a download file describes itself: the header comment, the definitions
section, and assign_columns.  CSVLanguage.assign_columns uses it to annotate
each grouped header cell with its ordered subcolumn names, keeping one CSV
field per top-level column so the data shape and the knowl hyperlinks are
unchanged.

The first entry of each subgroup group downloads the raw [label, TeX name] pair
rather than the displayed link, so sub_name, ambient_name and quotient_name now
carry a download_desc spelling out that pair, including when the label is null
(group not in the LMFDB) and when both entries are null (quotient of a
non-normal subgroup).

Verified by generating subgroup downloads in all seven offered formats and
checking that number field (ordinary columns) and cmf (ColGroups with a
download_col) downloads are byte-identical in all seven formats.  Adds four
tests, all of which fail against the download machinery as it was before this
branch: the text header/definitions/row lengths, the CSV header parsed with the
csv module, the scalar ColGroup non-regression, and the download_subcols
contract.  pyflakes, pylint and ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@roed-math

Copy link
Copy Markdown
Owner Author

Thanks for the review. All three points are addressed in the new commit, and the PR description now covers the added tests and the formats verified.

1. CSV is now self-describing. The schema is no longer prose passed to lang.comment. Downloader.make_schema builds one ColumnSchema per downloaded column (storage name, display title, and, for a group that downloads as a nested list, the ordered subcolumn schemas), and that same object drives the header comment, the definitions section and assign_columns. Since CSVLanguage.comment returns nothing, CSVLanguage.assign_columns uses the schema to annotate each grouped header cell:

"=HYPERLINK(...,""label"")","subgroup_cols [sub_name, subgroup_order, sylow, normal, ...]","ambient_cols [ambient_name, ambient_order]","quotient_cols [quotient_name, quotient_order, minimal_normal, ...]"

There is still exactly one CSV field per top-level column, so the rows are not flattened; ordinary headers and the knowl hyperlinks are untouched, and groups with a download_col stay scalar. The comment-based prose for the other languages is unchanged, and is generated from the same schema rather than duplicated.

2. The [label, TeX name] pairs are documented. sub_name, ambient_name and quotient_name now set a download_desc:

A two-element list [label, name] for the subgroup as an abstract group: its LMFDB label, followed by its name formatted in TeX (see the group.name knowl for the conventions used in these names).
The label is null when the abstract group is not in the LMFDB; the name is still given in that case.

with the quotient adding that both entries are null when the subgroup is not normal. Both null cases are real in the data (for example 4096.c.2.A has a null subgroup label with the name still present, and the quotient pair is null throughout 8.3.4.b1.a1). The stored values and their order are unchanged.

3. Tests. Four new tests, all of which fail against the download machinery as it was before this branch:

  • test_subgroup_search_download_text: the top-level form, ordered group expansions (first and last subcolumn plus representative ones in between), the grouped-column introductions, per-subcolumn definitions, the [label, TeX name] descriptions, and that each downloaded row matches the documented top-level and per-group lengths.
  • test_subgroup_search_download_csv: parsed with the csv module rather than by substring, checking the four header fields, the ordinary label cell, the ordered grouped schemas, and equal field counts in the data rows.
  • test_scalar_colgroup_download: cmf traces/atkin_lehner and conjugacy class power_cols keep their download_col, report no subcolumns and download a single value.
  • test_download_subcols in lmfdb/tests/test_utils.py: the four-case API contract.

All are bounded to the subgroups of a single group (8.3) and avoid timestamps.

Verification.

  • Subgroup downloads generated in all seven offered formats (text, csv, sage, magma, gp, gap, oscar). The generated sage file still loads and runs: make_data() returns records keyed by label/subgroup_cols/ambient_cols/quotient_cols, with subgroup_cols holding exactly the 18 documented entries.
  • Number field (ordinary columns) and cmf (ColGroups with a download_col) downloads are byte-identical in all seven formats to the previous head, so the assign_columns refactor changed nothing outside the grouped case.
  • The conjugacy class download, the one group that is both callable-subcols and download_together, still emits Powers as a single value with no expansion and a plain knowl hyperlink in its CSV header.
  • lmfdb/groups/abstract/test_abstract_groups.py and lmfdb/tests/test_utils.py pass in full (30 tests), as do the cmf and number field download tests. pyflakes, pylint (with CI's flags) and ruff are clean.

One judgement call worth flagging: download_desc replaces the column knowl in the definitions section rather than adding to it, so the three name columns no longer dump the group.name knowl (25 lines, including raw <ul>/<li> HTML) three times. The new text points at that knowl by name instead. Happy to keep the knowl text as well if you would rather not lose it inline.

@roed314

roed314 commented Aug 5, 2026

Copy link
Copy Markdown

GPT signed off.

@roed-math

Copy link
Copy Markdown
Owner Author

Superseded by LMFDB#7166, opened upstream from this same branch. Closing here; review continues upstream.

@roed-math roed-math closed this Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants